基础知识_数据库

文章目录
  1. 1. 数据库原理
    1. 1.1. 数据库设计的三大范式
    2. 1.2. 不遵守三大范式会带来哪些问题
    3. 1.3. 如何理解数据库索引
    4. 1.4. 数据库事务以及四大特性
    5. 1.5. 并发一致性问题
    6. 1.6. 事务的四种隔离级别
    7. 1.7. 两种封锁类型:读写锁和意向锁
      1. 1.7.1. 读写锁
      2. 1.7.2. 意向锁
      3. 1.7.3. 参考
    8. 1.8. 隐式锁定&显示锁定
    9. 1.9. 封锁协议
      1. 1.9.1. 一级封锁协议
      2. 1.9.2. 二级封锁协议
      3. 1.9.3. 三级封锁协议
      4. 1.9.4. 两阶段封锁协议
    10. 1.10. MVCC
  2. 2. SQL语句
    1. 2.1. 数据库相关操作
    2. 2.2. 数据表相关操作
    3. 2.3. 插入数据
    4. 2.4. 查询数据
    5. 2.5. WHERE子句
    6. 2.6. 修改数据
    7. 2.7. 删除数据
    8. 2.8. LIKE子句
    9. 2.9. UNION
    10. 2.10. 排序
    11. 2.11. 分组
    12. 2.12. 连接
    13. 2.13. NULL值判断
    14. 2.14. 正则表达式
    15. 2.15. 事务
    16. 2.16. ALTER 命令
    17. 2.17. 索引
    18. 2.18. 临时表
    19. 2.19. 复制表
    20. 2.20. 获取服务器原数据
    21. 2.21. 删除重复数据
    22. 2.22. 导入导出数据
  3. 3. LeetCode题解
  4. 4. Mysql
    1. 4.1. b树与b+树对比
    2. 4.2. 为什么数据库普遍不用红黑树作索引
    3. 4.3. 为什么数据库一般不用hash表作索引
    4. 4.4. STL为什么用红黑树实现map、set,不用平衡二叉树。
  5. 5. 参考

数据库笔记。

数据库原理

数据库设计的三大范式

  • 第一范式:确保每列保持原子性。比如存储地址时,如果省市区都放到一列里,如果需要读取省份时,就比较麻烦了,这样就不符合原子性了。所以应当把省份、市、区、详细地址分别放到不同的列中。
  • 第二范式:确保每列数据完全依赖于主键,而不是依赖主关键字的一部分。如果有两个联合主键a和b,又有数据列c依赖a,d依赖b,就应该把他们分成两个表。
  • 第三范式:除主键外的其他列之间不应该有依赖关系。
  • 每个范式都建立在前一范式的基础上。在实际应用中不一定要完全遵守三大范式,虽然可能会有数据冗余,但是能提高查询效率。

不遵守三大范式会带来哪些问题

学号 姓名 班级 班主任 课程 分数
001 萧炎 一班 药老 青莲地心火 100
001 萧炎 一班 药老 净莲妖火 100
002 林动 二班 天蚕土豆 通背拳 100
002 林动 二班 天蚕土豆 大荒囚天指 100
003 谢文东 三班 六道 坏蛋是怎样炼成的 100

如上表格:

  • 冗余数据。班级、班主任都因为课程出现数据冗余。
  • 插入异常。如果增加一个未选课的学生,就无法插入数据。
  • 删除异常。如果撤销一个班主任,会丢失学生的信息。
  • 修改异常。修改一个学生的班主任时,会有另一条记录未被修改。

如何理解数据库索引

数据库事务以及四大特性

1.事务

  • 事务是满足ACID特性的一组sql操作。

2.事务四大特性

  • 原子性(atomicity):一个事务必须视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。
  • 一致性(consistency):数据库总数从一个一致性的状态转换到另一个一致性的状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。(所谓一致性可以说是一种正确地状态,所谓正确,就是满足一定的约束条件)
  • 隔离性(isolation):一个事务所做的修改在最终提交以前,对其他事务是不可见的。
  • 持久性(durability):一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。

3.四个特性的关系

  • 在无并发的情况下,保证原子性就能实现一致性。
  • 有并发时保证原子性和隔离性才能实现一致性。
  • 实现一致性才能保证结果的正确。
  • 持久性保证数据库崩溃后数据不会丢失。

并发一致性问题

1.1第一类丢失更新(回滚导致丢失)。T1回滚导致T2提交的修改丢失了。

1
2
3
4
T1        T2
修改var
修改var
回滚

1.2第二类丢失更新(覆盖导致丢失)。T1对var的修改被T2提交的修改覆盖了,这是不可重复读的一种特殊情况。

1
2
3
4
T1        T2
修改var
修改var
读取var

2.脏读,又称无效数据读出。一个事务读取另外一个事务还没有提交的数据叫脏读。

1
2
3
4
T1        T2
修改var
读取var
回滚

3.不可重复读,一个事务读取了另一个事务提交的数据。

1
2
3
4
T1        T2
读取var
修改var
读取var

4.幻读,读取到了不存在的数据。

1
2
3
4
T1            T2
范围读取数据
插入一条数据
范围读取数据
  • 不可重复读跟幻读有点像,区别在于不可重复读是读取到了另一个事务的update操作,幻读是读取到了另一个事务的insert操作。

事务的四种隔离级别

数据库事务的隔离级别有4个,依次递增:

  • Read uncommitted,未提交读表示在一个事务中可以读取另一个事务未提交的数据,存在脏读、不可重复读、幻读的问题。
  • Read committed,提交读表示一个事务中可以读取另一事务已提交的数据,存在不可重复读、幻读的问题。
  • Repeatable read,可重复读保证一个事务中多次读取的结果是相同的,还存在幻读的问题。
  • Serializable,强制事务串行化,一般不用这个隔离级别。
隔离级别 脏读 不可重复读 幻影读 丢失更新 第二类丢失更新
未提交读 x x
提交读 × x x
可重复读 × × x x
可串行化 × × × x x

参考:三级封锁协议两段锁以及隔离级别

PS:我的理解是未提交读采用一级封锁协议就已经解决了丢失更新问题,但是网上很多人的总结”提交读”级别还存在第二类丢失更新问题?

两种封锁类型:读写锁和意向锁

Mysql提供两种封锁粒度,分别是行级锁和表级锁。

当访问数据的时候,尽量加锁小的范围可以减少性能的损耗,所以加锁的时候需要在锁开销和并发程度之间做一个平衡。

读写锁
  • 读锁又叫共享锁(Shared Lock,简称S锁),可以加在表上,也可以加在行上。
  • 写锁又叫排它锁(Exclusive Lock,简称X锁),可以加在表上,也可以加在行上。

如果事务T1对数据A加了共享锁,T2可以对数据A再加共享锁,但是不能再加排他锁。

如果事务T2对数据A加了排它锁,T2不可以再加共享锁或排它锁。

两者的兼容关系如下:

- S X
S ×
X × ×
意向锁

1.如果事务T1对表的第5行加了排它锁,T2又想对表加排它锁/共享锁,T2需要检查两件事:

  • 表上是否有表级的排它锁。
  • 表中某一行是否加了排它锁。

在判断第二点的时候,需要遍历表中的每一行才能判断,这样的开销太大了。如果能给表加一个标志,用来标志表内某一行是否有排它锁。这样就产生了意向锁。

2.意向锁分为以下两种:

  • 意向共享锁(Intention Shared Lock,简称IS),只能是表锁。
  • 意向排他锁(Intention Exclusive Lock,简称IX),只能是表锁。

事务T在获取某行的S锁之前,需要先获取该表的IS锁或者IX锁。

事务T在获取某行的X锁之前,需要先获取该表的IX锁。

PS:S和X是我们要手动去加的,IS和IX是数据库根据我们的操作自动去加的。

3.意向锁只是一个标志,表示表上已经加了或即将要加共享锁/排它锁,所以意向锁之间相互兼容:

- IS IX
IS
IX

4.意向锁和表级的共享锁排它锁之间的兼容关系如下:

- IS IX
S x
X x x
参考

隐式锁定&显示锁定

InnoDB会根据隔离级别在合适的时候进行加锁和解锁,这是隐式锁定。我们也可以通过Sql语句显示加锁。

1
2
SELECT ... LOCK IN SHARE MODE;  #添加共享锁
SELECT ... FOR UPDATE; #添加排它锁

封锁协议

了解读写锁和意向锁的概念后,何时加锁何时解锁还是个问题。有三级封锁协议,分别对应几种隔离级别。

一级封锁协议
  • 事务T修改数据时要加X锁,直到事务T结束才释放锁。

一级封锁协议要求修改数据时必须要加锁,能够避免丢失修改问题,对应”未提交读”隔离级别。

T1 T2
lockX(var)
修改var lockX(var)
提交 阻塞
unlockX(var)
获得锁
修改var
提交
unlockX(var)
二级封锁协议

二级封锁协议要求在一级封锁协议基础上再加一条:

  • 事务T读取数据时要加S锁,读取结束释放锁。

这样事务T1在写数据时已经加了X锁,事务T2想要读取数据在加S锁时会阻塞,能够避免脏读问题。这对应了“提交读”的隔离级别。

T1 T2
lockX(var)
修改var lockS(var)
回滚 阻塞
unlockX(var)
获得锁
读取var
提交
unlockS(var)
三级封锁协议

三级封锁协议要求在一级封锁协议的基础上再加一条:

  • 事务T读取数据时要加S锁,直到事务结束释放S锁。

二级封锁协议在读取结束后就释放S锁,还会存在不可重复读问题:事务T2对数据加S锁,读取结束释放S锁。事务T1加X锁修改数据,T1结束释放X锁。事务T2又加S锁重复读取数据,这时T2在一个事务里就两次读到了不同的数据。

三级封锁协议要求在事务结束后释放S锁,就避免了读数据过程中其他事务来修改数据。解决了不可重复读的问题,对应”可重复读”隔离级别。

疑问:三级封锁协议并不能阻止幻读,修改的不能再被读取,但是新增(删除)的记录数可以统计。为什么三级封锁协议不能阻止幻读,insert和delete操作是如何加锁的?

T1 T2
lockS(var)
读取var
lockX(var)
阻塞
读取var
提交
unlockS(var)
获得锁
修改var
提交
unlockX(var)
两阶段封锁协议

该协议要求一个事务分为加锁(生长阶段)和解锁(衰退阶段)两个阶段,也就是在一个事务里,任何一个加锁都在解锁前面。

事务满足两阶段封锁协议>>串行化调度,反之就不一定了。该协议可以满足”可串行化”隔离级别。

MVCC

xxx

SQL语句

数据库相关操作

  • 判断mysql是否启动

    1
    ps -ef | grep mysqld
  • 启动mysql服务器

    1
    2
    cd /usr/bin
    ./mysqld_safe &
  • 关闭mysql服务器

    1
    2
    3
    cd /usr/bin
    ./mysqladmin -u root -p shutdown
    Enter password: ******
  • 启动mysql终端

    1
    mysql -u root -p
  • 退出mysql终端

1
mysql>exit
  • 创建数据库
1
2
3
4
#sql语句创建
CREATE DATABASE 库名;
#命令行直接创建
mysqladmin -u root -p create 库名
  • 删除数据库
1
2
3
DROP DATABASE 库名;
#命令行删除
mysqladmin -u root -p drop 库名;
  • 打印所有数据库名
1
SHOW DATABASES;
  • 选择数据库
1
USE 库名;

数据表相关操作

  • 查看、修改表属性
1
2
SHOW TABLE STATUS LIKE '表名';
ALTER TABLE 表名 ENGINE=InnoDB;
  • 创建表
1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE IF NOT EXISTS `test_tbl`(
`test_id` INT UNSIGNED AUTO_INCREMENT,
`test_title` VARCHAR(100) NOT NULL,
`test_author` VARCHAR(40) NOT NULL,
`submission_date` DATE,
PRIMARY KEY ( `test_id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
============================================================
如果你不想字段为 **NULL** 可以设置字段的属性为 **NOT NULL**, 在操作数据库时如果输入该字段的数据为**NULL** ,就会报错。
AUTO_INCREMENT定义列为自增的属性,一般用于主键,数值会自动加1。
PRIMARY KEY关键字用于定义列为主键。 您可以使用多列来定义主键,列间以逗号分隔。
ENGINE 设置存储引擎,CHARSET 设置编码。
  • 查看表的字段
1
SHOW COLUMNS FROM test;
  • 删除表
1
DROP TABLE 表名;

插入数据

1
2
3
4
INSERT INTO test_tbl
(test_title,test_author,submission_date)
VALUES
("study sql","YIFEI",NOW());

查询数据

1
2
3
4
5
6
7
8
9
10
11
12
#SELECT语法
SELECT column_name,column_name
FROM table_name
[WHERE Clause]
[LIMIT N][ OFFSET M]
============================================
查询语句中你可以使用一个或者多个表,表之间使用逗号(,)分割,并使用WHERE语句来设定查询条件。
SELECT 命令可以读取一条或者多条记录。
你可以使用星号(*)来代替其他字段,SELECT语句会返回表的所有字段数据
你可以使用 WHERE 语句来包含任何条件。
你可以使用 LIMIT 属性来设定返回的记录数。
你可以通过OFFSET指定SELECT语句开始查询的数据偏移量。默认情况下偏移量为0
1
2
3
SELECT * FROM 表名;
SELECT column1,column2 FROM 表名;
SELECT DISTINCT column1,coulumn2 FROM 表名;

WHERE子句

  • 单表

    1
    2
    3
    4
    5
    6
    7
    8
    SELECT test_author,test_id FROM test_tbl
    WHERE BINARY test_title='study php' AND
    BINARY test_author='YIFEI'
    =======================================
    多个条件用ANDOR连接。
    =检测是否相等,<>、!=检测不等,其他还有<=、>=。
    BINARY表示区分大小写。
    WHERE也可以用于DELETE 或者 UPDATE中。
  • 多表

修改数据

1
2
3
UPDATE test_tbl 
SET test_title='study cpp',test_author='tws'
WHERE test_id=2;

删除数据

1
DELETE FROM test_tbl WHERE test_id=3;

LIKE子句

  • 使用%匹配任意字符
1
SELECT * FROM test_2 WHERE submission_date LIKE "%08-26";

UNION

  • 联合查询
1
2
3
4
5
6
7
8
SELECT submission_date FROM test_2
UNION all
SELECT submission_date FROM test_tbl
ORDER BY submission_date;
====================================
all是显示所有数据,默认为distinct去重。
两个select查询的列数应当相同。
ORDER BY submission_date是按照该列排序。
  • 带有WHERE的联合查询
1
2
3
4
5
6
SELECT country, name FROM Websites
WHERE country='CN'
UNION ALL
SELECT country, app_name FROM apps
WHERE country='CN'
ORDER BY country;

排序

  • 升序排列
1
2
3
4
SELECT * FROM test_tbl ORDER BY name DESC,date ASC;
===========================================================
ASC升序排列,DESC为降序排列。
如果排序列为汉字,想要按照拼音排序:ORDER BY CONVERT(title using gbk);

分组

  • 分组并统计个数
1
2
3
4
SELECT name,COUNT(*) FROM employee_tbl GROUP BY name;
======================================================
按照名字分组。
count(*)统计每类的数量。
  • 使用WITH ROLLUP,在group by的结果之上再统计。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SELECT coalesce(name, '总数'), SUM(singin) as singin_count FROM  employee_tbl GROUP BY name WITH ROLLUP;
+--------------------------+--------------+
| coalesce(name, '总数') | singin_count |
+--------------------------+--------------+
| 小丽 | 2 |
| 小明 | 7 |
| 小王 | 7 |
| 总数 | 16 |
+--------------------------+--------------+
4 rows in set (0.01 sec)
==================================================
coalesce(a,b,c)如果a!=null就使用a作为该列名称,如上如果name为空,就使用"总数"作列名。
ifnull(a,b)跟coalesce一样的效果。
WITH ROLLUP之后可以对分组结果再统计SUM(singin)。
SUM之外还有AVGCOUNT等。

连接

内连接

1
2
3
SELECT a.runoob_id,a.runoob_title,b.runoob_author 
FROM runoob_2 AS a INNER JOIN runoob_tbl AS b
ON BINARY a.runoob_author=b.runoob_author;

内连接是取两表的交集,上面语句等价于以下WHERE语句:

1
2
3
SELECT a.runoob_id,a.runoob_title,b.runoob_author 
FROM runoob_2 AS a,runoob_tbl AS b
WHERE BINARY a.runoob_author=b.runoob_author;

左连接

1
2
3
SELECT a.runoob_id,a.runoob_title,b.runoob_author 
FROM runoob_2 AS a LEFT JOIN runoob_tbl AS b
ON BINARY a.runoob_author=b.runoob_author;

左连接会选取左表全部,输出右表满足要求的。

右连接

1
2
3
SELECT a.runoob_id,a.runoob_title,b.runoob_author 
FROM runoob_2 AS a RIGHT JOIN runoob_tbl AS b
ON BINARY a.runoob_author=b.runoob_author;

NULL值判断

在WHERE子句中判断某值为空时不能WHERE name=null,应当使用如下方式:

1
2
3
4
5
SELECT * FROM test WHERE name IS NULL;
=============================================
**IS NULL:** 当列的值是 NULL,此运算符返回 true。
**IS NOT NULL:** 当列的值不为 NULL, 运算符返回 true。
**<=>:** 比较操作符(不同于 = 运算符),当比较的的两个值相等或者都为 NULL 时返回 true。

正则表达式

1
SELECT * FROM runoob_2 WHERE runoob_author REGEXP '^y';
模式 描述
^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 ‘\n’ 或 ‘\r’ 之后的位置。
$ 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 ‘\n’ 或 ‘\r’ 之前的位置。
. 匹配除 “\n” 之外的任何单个字符。要匹配包括 ‘\n’ 在内的任何字符,请使用像 ‘[.\n]’ 的模式。
[…] 字符集合。匹配所包含的任意一个字符。例如, ‘[abc]’ 可以匹配 “plain” 中的 ‘a’。
[^…] 负值字符集合。匹配未包含的任意字符。例如, ‘[^abc]’ 可以匹配 “plain” 中的’p’。
p1|p2|p3 匹配 p1 或 p2 或 p3。例如,’z|food’ 能匹配 “z” 或 “food”。’(z|f)ood’ 则匹配 “zood” 或 “food”。
* 匹配前面的子表达式零次或多次。例如,zo 能匹配 “z” 以及 “zoo”。 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,’zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,’o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。

事务

设置隔离级别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
查看当前会话隔离级别:
select @@tx_isolation;
查看系统的隔离级别:
select @@global.tx_isolation;
设置会话的隔离级别,隔离级别由低到高设置依次为:
set session transaction isolation level read uncommitted;
set session transaction isolation level read committed;
set session transaction isolation level repeatable read;
set session transaction isolation level serializable;
设置当前系统的隔离级别,隔离级别由低到高设置依次为:
set global transaction isolation level read uncommitted;
set global transaction isolation level read committed;
set global transaction isolation level repeatable read;
set global transaction isolation level serializable;

事务控制语句

1
2
3
4
5
6
7
8
9
10
11
1、用 BEGIN, ROLLBACK, COMMIT来实现
BEGIN 开始一个事务
ROLLBACK 事务回滚
COMMIT 事务确认
2、直接用 SET 来改变 MySQL 的自动提交模式:
SET AUTOCOMMIT=0 禁止自动提交
SET AUTOCOMMIT=1 开启自动提交
3、保存点
SAVEPOINT identifier,SAVEPOINT 允许在事务中创建一个保存点,一个事务中可以有多个 SAVEPOINT
RELEASE SAVEPOINT identifier 删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
ROLLBACK TO identifier 把事务回滚到标记点;

ALTER 命令

  • 查看表字段
1
SHOW COLUMNS FROM testalter_tbl;
  • 添加表字段
1
2
ALTER TABLE runoob_1 
ADD i INT AFTER runoob_id;

可以将AFTER runoob_id改为FIRST,插入到第一列,默认是末尾。

  • 删除表字段
1
2
ALTER TABLE testalter_tbl 
DROP i;
  • MODIFY修改表字段
1
2
3
4
5
ALTER TABLE testalter_tbl 
MODIFY c CHAR(10);
#修改字段位置
ALTER TABLE test
MODIFY name1 type1 AFTER name2;
  • CHANGE修改表字段
1
2
ALTER TABLE testalter_tbl 
CHANGE i j BIGINT;

CHANGE 关键字之后,紧跟着的是你要修改的字段名,然后指定新字段名及类型。

  • 修改字段默认值
1
2
ALTER TABLE testalter_tbl 
ALTER i SET DEFAULT 1000;
  • 修改表名
1
2
ALTER TABLE testalter_tbl 
RENAME TO alter_tbl;
  • 查看表属性
1
SHOW TABLE STATUS LIKE 'testalter_tbl'
  • 修改表属性
1
2
ALTER TABLE testalter_tbl 
ENGINE = MYISAM;
  • 删除外键约束
1
2
ALTER TABLE talbename
DROP FOREIGN KEY keyname;

索引

  • 查看索引
1
SHOW INDEX FROM table_name;
  • ALTER添加索引
1
2
3
4
5
6
#添加普通索引,索引值可出现多次。
ALTER TABLE tbl_name ADD INDEX index_name (column_list);
#添加唯一索引,创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)。
ALTER TABLE tbl_name ADD UNIQUE index_name (column_list);
#添加全文索引
ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list);
  • ALTER删除索引
1
ALTER TABLE tbl_name DROP INDEX index_name;
  • ALTER添加删除主键
1
2
3
4
#添加主键,首先确保主键列不为空。
ALTER TABLE testalter_tbl MODIFY i INT NOT NULL;
ALTER TABLE tbl_name ADD PRIMARY KEY (column_list);
ALTER TABLE testalter_tbl DROP PRIMARY KEY;
  • CREATE创建索引
1
CREATE INDEX indexName ON table_name (column_name);
  • DROP删除索引
1
DROP INDEX [indexName] ON table_name;
  • 创建表时指定索引
1
2
3
4
5
CREATE TABLE mytable(
ID INT NOT NULL,
username VARCHAR(16) NOT NULL,
INDEX [indexName] (username(length))
);

临时表

  • 临时表创建、插入、删除。(无法通过show tables查看)
1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE TEMPORARY TABLE SalesSummary (
product_name VARCHAR(50) NOT NULL,
total_sales DECIMAL(12,2) NOT NULL DEFAULT 0.00,
avg_unit_price DECIMAL(7,2) NOT NULL DEFAULT 0.00,
total_units_sold INT UNSIGNED NOT NULL DEFAULT 0
);
INSERT INTO SalesSummary
(product_name, total_sales, avg_unit_price, total_units_sold)
VALUES
('cucumber', 100.25, 90, 2);
SELECT * FROM SalesSummary;
DROP TABLE SalesSummary;
SELECT * FROM SalesSummary;
  • 用查询直接创建临时表
1
2
3
4
CREATE TEMPORARY TABLE aaa AS(
SELECT * FROM runoob_1
LIMIT 1,10000
);

复制表

法一:执行sql创建新表、再插入数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#输出该表的创建语句
SHOW CREATE TABLE runoob_tbl \G;
#修改表名,然后执行sql语句
CREATE TABLE `clone_tbl` (
`runoob_id` int(11) NOT NULL auto_increment,
`runoob_title` varchar(100) NOT NULL default '',
`runoob_author` varchar(40) NOT NULL default '',
`submission_date` date default NULL,
PRIMARY KEY (`runoob_id`),
UNIQUE KEY `AUTHOR_INDEX` (`runoob_author`)
) ENGINE=InnoDB;
#将原表数据插入到新表
INSERT INTO clone_tbl (runoob_id,runoob_title,runoob_author,submission_date)
SELECT runoob_id,runoob_title,runoob_author,submission_date FROM runoob_tbl;

法二:复制表结构、再插入数据

1
2
CREATE TABLE targetTable LIKE sourceTable;
INSERT INTO targetTable SELECT * FROM sourceTable;

法三:复制表结构和数据

1
CREATE TABLE new_name SELECT * FROM old_name;

创建新表并修改字段名

1
2
3
CREATE TABLE newadmin(
SELECT id, username AS uname, password AS pass FROM admin
)

获取服务器原数据

SELECT VERSION( ) 服务器版本信息
SELECT DATABASE( ) 当前数据库名 (或者返回空)
SELECT USER( ) 当前用户名
SHOW STATUS 服务器状态
SHOW VARIABLES 服务器配置变量

删除重复数据

1
2
3
4
5
6
7
CREATE TABLE tmp
SELECT last_name, first_name, sex FROM person_tbl
GROUP BY (last_name, first_name, sex);

DROP TABLE person_tbl;

ALTER TABLE tmp RENAME TO person_tbl;

导入导出数据

导出数据

  • 查看数据库默认文件路径
1
show variables like 'datadir';
  • 导出数据表数据
1
2
SELECT * FROM table_name
INTO OUTFILE 'table.txt';
  • 指定格式导出表数据
1
2
3
4
SELECT a,b,a+b INTO OUTFILE '/tmp/result.text'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM test_table;
  • mysqldump导出表sql
1
mysqldump -uroot -proot 数据库名 数据表名 > tmp.txt
  • mysqldump导出数据库sql
1
2
3
4
#导出数据库
mysqldump -uroot -proot 数据库名 > tmp.txt
#导入数据库(库名要先手动创建)
mysql -u root -p database_name < tmp.txt
  • 备份所有数据库
1
mysqldump -u root -p --all-databases > database_dump.txt
  • 备份远程数据库
1
mysqldump -h other-host.com -P port -u root -p database_name > dump.txt

导入数据

  • 导入库sql
1
2
#导入数据库(库名要先手动创建)
mysql -u root -p database_name < tmp.txt
  • source导入sql
1
2
3
4
CREATE DATABASE abc;
USE abc;
SET NAMES utf8;
SOURCE /tmp/tmp.txt
  • LOAD DATA导入数据
1
LOAD DATA LOCAL INFILE 'dump.txt' INTO TABLE mytbl;

LeetCode题解

  • 1179. Reformat Department Table
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # Write your MySQL query statement below
    select id,
    max(case when month='Jan' then revenue end) as Jan_Revenue,
    max(case when month='Feb' then revenue end) as Feb_Revenue,
    max(case when month='Mar' then revenue end) as Mar_Revenue,
    max(case when month='Apr' then revenue end) as Apr_Revenue,
    max(case when month='May' then revenue end) as May_Revenue,
    max(case when month='Jun' then revenue end) as Jun_Revenue,
    max(case when month='Jul' then revenue end) as Jul_Revenue,
    max(case when month='Aug' then revenue end) as Aug_Revenue,
    max(case when month='Sep' then revenue end) as Sep_Revenue,
    max(case when month='Oct' then revenue end) as Oct_Revenue,
    max(case when month='Nov' then revenue end) as Nov_Revenue,
    max(case when month='Dec' then revenue end) as Dec_Revenue
    from department
    group by id

Mysql

b树与b+树对比

  • b+树的非叶子结点存储数据,所有相对于b树的结点,b+树的非叶子结点可以存储更多的索引,这样b+树会更矮更宽。
  • b+树每次操作都是o(logn)时间复杂度,是稳定的,b树的时间复杂度在o(1)~o(logn)之间。
  • b+树的所有叶子结点被链表串起来,更适合范围查询。

为什么数据库普遍不用红黑树作索引

为什么数据库一般不用hash表作索引

  • hash表在单词查询是时间复杂度是o(1),但是在范围查询时是o(n),数据库经常需要范围查询。

STL为什么用红黑树实现map、set,不用平衡二叉树。

  • 平衡二叉树维护树完全平衡,但是这样就给每次操作带来了较大的常数时间,所以采用大体上平衡的红黑树反而效率更高。

参考